package com.tkjt.pms.calc.core;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tkjt.pms.common.entity.TkIndexValueAttrs;
import com.tkjt.pms.modules.common.service.TkIndexValueAttrsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.tkjt.pms.calc.CalcDataUpdater;
import com.tkjt.pms.calc.CalcTraceUpdater;
import com.tkjt.pms.calc.FormulaExecutor;
import com.tkjt.pms.calc.common.IndexCalcConsts;
import com.tkjt.pms.calc.common.IndexCalcParallel;
import com.tkjt.pms.calc.formula.FormulaEngine;
import com.tkjt.pms.calc.formula.common.EngineResult;
import com.tkjt.pms.calc.formula.common.FormulaConsts;
import com.tkjt.pms.calc.formula.common.FormulaRule;
import com.tkjt.pms.calc.formula.common.FormulaRules;
import com.tkjt.pms.calc.formula.common.FormulaValue;
import com.tkjt.pms.calc.formula.utils.FormulaParamHelper;
import com.tkjt.pms.calc.loader.FormulaDataLoader;
import com.tkjt.pms.calc.loader.FormulaRuleLoader;
import com.tkjt.pms.common.IndexParam;
import com.tkjt.pms.utils.EsExceptionUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class FormulaExecutorImpl implements FormulaExecutor {

	@Autowired
	private FormulaRuleLoader formulaRuleLoader;
	@Autowired
	private FormulaDataLoader formulaDataLoader;
	@Autowired
	private Map<String, FormulaEngine> formulaEngines = new HashMap<String, FormulaEngine>();
	@Autowired
	private CalcDataUpdater calcDataUpdater;
	@Autowired
	private CalcTraceUpdater calcTraceUpdater;
	@Autowired
	private TkIndexValueAttrsService tkIndexValueAttrsService;

	@Override
	public boolean doExecutor(IndexParam indexParam, IndexCalcParallel indexCalcParallel) {
		
		/********************************************************************************************************
		 * Step 1: 加载数据项计算对应的配置公式
		 */
		FormulaRules formulaRules = null;
		{
			String exception = null;
			try {
				formulaRules = formulaRuleLoader.doLoader(indexCalcParallel);
				indexParam.addParam(IndexCalcConsts.PARAM_CALC_CONFIG_RULES, formulaRules);
			} catch (Exception e) {
				log.error(e.getMessage(), e);
				exception = EsExceptionUtils.formatException(e);
			}
			if (null != exception) {
				calcTraceUpdater.updateException(indexParam, indexCalcParallel, exception);
				return false;
			}
		}
		if(formulaRules.isEmpty()) {
			log.warn("formular rules is empty, indexCalcParallel={}", indexCalcParallel);
			return true;
		}
		/********************************************************************************************************
		 * Step 2: 处理需要计算的[DataColumn], 必须为List类型( 月份列、季度列、累计列)
		 */
		//todo 目前该方法没用到
		/*List<String> calcWhichDatas = FormulaParamHelper.getCalcWhichDatas(indexParam);
		if (calcWhichDatas == null) {

		}*/
		List<String> calcWhichDatas = FormulaConsts.calcWhichDatas;
		indexParam.addParam(FormulaConsts.ITEM_CONFIG_WHICH_DATAS, calcWhichDatas);
		/********************************************************************************************************
		 * Step 3: 按指定的顺序计算： 月份列、季度列、累计列
		 */
		for (String whichData : calcWhichDatas) {
			// 设置当前计算的[WhichData]
			// indexParam = FormulaParamHelper.setFormulaCurrentWhichData(indexParam, whichData);
			FormulaRule formulaRule = formulaRules.searchRule(whichData, indexCalcParallel.getIndexValueCode(), indexCalcParallel.getIndexDepart());
			if (null == formulaRule || StringUtils.isEmpty(formulaRule.getFormula())) {
				log.warn("search rule null, whichData={},indexCalcParallel={}", whichData, indexCalcParallel);
				continue;
			}
			if(whichData.equals("Mi") && (indexCalcParallel.getIndexValueCode().equals("KCIAAA001VA001") || indexCalcParallel.getIndexValueCode().equals("KCIAAA002VA001") || indexCalcParallel.getIndexValueCode().equals("KGIAAA001VA001")  || indexCalcParallel.getIndexValueCode().equals("KGIAAA002VA001")) && indexCalcParallel.getDataType().equals("budget")){
				log.warn("预期收入-联考目标值和EBITDA-联考目标值不进行计算, whichData={},indexCalcParallel={}", whichData, indexCalcParallel);
				continue;
			}
			indexParam = FormulaParamHelper.setFormulaCurrentWhichData(indexParam, whichData);
			boolean whichDataRet = this.doWhichDataExecutor(indexParam, formulaRule, indexCalcParallel);
			if (whichDataRet) {
				calcTraceUpdater.updateCalcTraceSuccess(indexParam, indexCalcParallel);
			} else {
				calcTraceUpdater.updateCalcTraceException(indexParam, indexCalcParallel);
				return false;
			}
			indexParam.removeParam(whichData);
		}

		return true;
	}

	public boolean doWhichDataExecutor(IndexParam indexParam, FormulaRule formulaRule, IndexCalcParallel indexCalcParallel) {

		String whichData = FormulaParamHelper.getFormulaCurrentWhichData(indexParam);
		/********************************************************************************************************
		 * Step 1: 加载公式计算所需要的数据
		 */
		FormulaValue formulaValue = null;

		indexParam = FormulaParamHelper.addFormulaRule(indexParam, whichData, formulaRule);
		formulaValue = formulaDataLoader.doLoader(formulaRule, indexCalcParallel);
		indexParam = FormulaParamHelper.addFormulaValue(indexParam, whichData, formulaValue);
		/*try {
			indexParam = FormulaParamHelper.addFormulaRule(indexParam, whichData, formulaRule);
			formulaValue = formulaDataLoader.doLoader(formulaRule, indexCalcParallel);
			indexParam = FormulaParamHelper.addFormulaValue(indexParam, whichData, formulaValue);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			String exception = EsExceptionUtils.formatException(e);
			indexParam = FormulaParamHelper.addFormulaException(indexParam, whichData, exception);
			return false;
		}*/
		/********************************************************************************************************
		 * Step 3: 执行计算，返回计算结果
		 */
		EngineResult engineResult = null;
		try {
			String engineCode = (String) indexParam.getParam(FormulaConsts.TYPE_ENGINE_EXCEL);
			if (StringUtils.isEmpty(engineCode)) {
				engineCode = FormulaConsts.TYPE_ENGINE_EXCEL;
			}
			log.info("engineCode = {}", engineCode);
			FormulaEngine formulaEngine = formulaEngines.get(engineCode);
			engineResult = formulaEngine.doExecutor(indexParam, formulaRule, formulaValue);
			indexParam = FormulaParamHelper.addFormulaResult(indexParam, whichData, engineResult);
			if(FormulaConsts.RET_FAIL.equals(engineResult.getRetCode())) {
				return false;
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			String exception = EsExceptionUtils.formatException(e);
			indexParam = FormulaParamHelper.addFormulaException(indexParam, whichData, exception);
			return false;
		}
		/********************************************************************************************************
		 * Step 4: 保存当前计算结果
		 */
		try {
			Map<String, Double> resultItems = engineResult.getCalcColumnValues();
			calcDataUpdater.doUpdater(indexParam, indexCalcParallel, resultItems);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			String exception = EsExceptionUtils.formatException(e);
			indexParam = FormulaParamHelper.addFormulaException(indexParam, whichData, exception);
			return false;
		}

		return true;
	}

}
